package com.a0soft.gphone.aTruffleHog.wnd.stat;
/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Copyright(C) 2011 
 *   Sam Lu <ysl.sam.lu (at) gmail.com>
 *
 */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.a0soft.gphone.aTruffleHog.R;
import com.a0soft.gphone.aTruffleHog.analytic.AnalyticsUtil;
import com.a0soft.gphone.aTruffleHog.di.DeviceInfo;
import com.a0soft.gphone.aTruffleHog.di.DeviceInfoKey;
import com.a0soft.gphone.aTruffleHog.srvc.HttpConnSrvc;
import com.a0soft.gphone.aTruffleHog.util.CONSTS;
import com.a0soft.gphone.aTruffleHog.util.aDebug;

import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class TopDeviceStatsFrg extends BaseStatFragment {
    protected static int TYPE_MY_COUNTRY = 1;
    protected static int TYPE_ALL_COUNTRIES = 2;
    
    private ArrayList<TopDeviceData>   m_data;
    
    private static final String OTHERS = "others";
    
    private static final String LOG_TAG = TopDeviceStatsFrg.class.getSimpleName();
    
    ////////////////////////////////////////
    public static TopDeviceStatsFrg 
    NewInstance(int nType) 
    {
        TopDeviceStatsFrg frg = new TopDeviceStatsFrg();
        SetType(frg, nType);
        return frg;
    }
    
    @Override public void 
    onActivityCreated(Bundle bdSavedInstanceState)
    {
        super.onActivityCreated(bdSavedInstanceState);
        if (aDebug.ENABLED) aDebug.d(LOG_TAG, "onActivityCreated(): m_nType=" + m_nType);

        AnalyticsUtil.GetInstance(getActivity()).TrackPageView(
            m_nType == TYPE_MY_COUNTRY ? AnalyticsUtil.PAGE_STAT_TOP_DEVICE_MY : 
                                         AnalyticsUtil.PAGE_STAT_TOP_DEVICE_ALL);
    }
    
    @Override public View 
    onCreateView(LayoutInflater inflater, ViewGroup vgContainer,
                 Bundle bdSavedInstanceState) 
    {
        View vRoot = super.onCreateView(inflater, vgContainer, bdSavedInstanceState);
        
        if (!getActivity().isFinishing())
            _GetTopDeviceStats(false);
        
        return vRoot;
    }
    
    private void
    _SetData(JSONObject json)
    {
        try {
            m_lDataTime = json.getLong("t");
            
            JSONArray data = json.getJSONArray("d");
            final int N = data.length();
            if (aDebug.ENABLED)
                aDebug.d(LOG_TAG, "N=" + N);
            
            if (N <= 0) {
                m_data = new ArrayList<TopDeviceData>(1);
            }
            else {
                m_data = new ArrayList<TopDeviceData>(N);
                for (int i = 0; i < N; i++) {
                    JSONObject obj = data.getJSONObject(i);
                    TopDeviceData td = new TopDeviceData();
                    td.m_fPercentage = (float)obj.getDouble("p");
                    td.m_lCount = obj.getLong("c");
                    td.m_strManufacture = obj.getString("m");
                    td.m_strModel = obj.getString("d");
                    td.m_strModelID = obj.getString(DeviceInfoKey.K.ST_MID);
                    
                    m_data.add(td);
                }
            }
        }
        catch (JSONException e) {
            if (aDebug.ENABLED)
                aDebug.d(LOG_TAG, "_SetData()", e);
            m_data = new ArrayList<TopDeviceData>(1);
        }
        SetStatData(m_data);
        
        Context ctx = getActivity();
        if (ctx == null) return;

        _AddFakeData(ctx);
        _MergeData(ctx);
        _SortData();
        
        DeviceInfo di = DeviceInfo.GetInstance(ctx);        
        String strModelID = di.GetString(DeviceInfoKey.K.ST_MID);
        String strManufacture = di.GetString(DeviceInfoKey.K.ST_MANUFACTURE);
        String strModel = di.GetString(DeviceInfoKey.K.ST_MODEL);
        if (!strModel.toLowerCase().startsWith(strManufacture.toLowerCase())) {
            strModel = strManufacture + " " + strModel;
        }
        Locale loc = new Locale(di.GetString(DeviceInfoKey.K.UR_LANG), 
                                di.GetString(DeviceInfoKey.K.UR_COUNTRY));
        m_strMy = getString(R.string.top_device_of_your_device, 
                            loc.getDisplayCountry(), 
                            strModel);
        
        m_nMyIdx = -1;
        final int N = m_data.size();
        for (int i = 0; i < N; i++) {
            TopDeviceData td = m_data.get(i);
            if (td.m_strModelID.equals(strModelID)) {
                m_nMyIdx = i;
                break;
            }
        }
        if (m_nMyIdx == -1) {
            //find others
            for (int i = N - 1; i >= 0; i--) {
                TopDeviceData td = m_data.get(i);
                if (td.m_strModelID.equals(OTHERS)) {
                    m_nMyIdx = i;
                    break;
                }
            }
        }
        
        SetDataFinished();
    }
    
    private void
    _SortData()
    {
        if (m_data.size() <= 1)
            return;
        
        Collections.sort(m_data, new Comparator<TopDeviceData>() {
            @Override public int 
            compare(TopDeviceData td1, TopDeviceData td2)
            {
                if (td1.m_strModelID.equals(OTHERS))
                    return 1;
                if (td2.m_strModelID.equals(OTHERS))
                    return -1;
                float f = td2.m_fPercentage - td1.m_fPercentage;
                if (f < 0) return -1; else if (f > 0) return 1;
                return td1.m_strModelID.compareTo(td2.m_strModelID);
            }
        });
    }
    
    private void
    _MergeData(Context ctx)
    {
        final int N = m_data.size();
        float fMinPercentage = Float.NaN;
        if (N > CONSTS.MAX_PIE_NUMBER) { 
            float[] fPercentages = new float[N];
            for (int i = 0; i < N; i++) {
                TopDeviceData td = m_data.get(i);
                fPercentages[i] = td.m_fPercentage;
            }
            Arrays.sort(fPercentages);
            fMinPercentage = fPercentages[N - CONSTS.MAX_PIE_NUMBER + 1];
            if (fMinPercentage < CONSTS.MIN_PIE_PERCENTAGE) {
                fMinPercentage = CONSTS.MIN_PIE_PERCENTAGE;
            }
        }
        else {
            for (TopDeviceData td: m_data) {
                if (td.m_fPercentage < CONSTS.MIN_PIE_PERCENTAGE) {
                    fMinPercentage = CONSTS.MIN_PIE_PERCENTAGE;
                    break;
                }
            }
        }
        if (Float.isNaN(fMinPercentage)) return;
        
        //find others and create if not exist
        TopDeviceData tdOthers = null;
        for (TopDeviceData td: m_data) {
            if (td.m_strModelID.equals(OTHERS)) {
                tdOthers = td;
                break;
            }
        }
        if (tdOthers == null) {
            tdOthers = new TopDeviceData();
            tdOthers.m_fPercentage = 0;
            tdOthers.m_lCount = 0;
            tdOthers.m_strModelID = OTHERS;
            tdOthers.m_strManufacture = OTHERS;
            tdOthers.m_strModel = OTHERS;
            
            m_data.add(tdOthers);
        }
        
        //merge
        ArrayList<TopDeviceData> tdToBeRemoved = new ArrayList<TopDeviceData>();
        for (TopDeviceData td: m_data) {
            if (!td.m_strModelID.equals(OTHERS)) {
                if (td.m_fPercentage < fMinPercentage) {
                    tdOthers.m_fPercentage += td.m_fPercentage;
                    tdOthers.m_lCount += td.m_lCount;
                    tdToBeRemoved.add(td);
                }
            }
        }
        m_data.removeAll(tdToBeRemoved);
    }
    
    private void
    _AddFakeData(Context ctx)
    {      
        DeviceInfo di = DeviceInfo.GetInstance(ctx);
        final String strModelID = di.GetString(DeviceInfoKey.K.ST_MID);
        final String strManufacture = di.GetString(DeviceInfoKey.K.ST_MANUFACTURE);
        final String strModel = di.GetString(DeviceInfoKey.K.ST_MODEL);
        
        //no stats, add current device info
        if (m_data.size() == 0) { 
            m_lDataTime = System.currentTimeMillis();
            
            TopDeviceData td = new TopDeviceData();
            td.m_lCount = 1;
            td.m_fPercentage = 1f;
            td.m_strModelID = strModelID;
            td.m_strManufacture = strManufacture;
            td.m_strModel = strModel;
            
            m_data.add(td);
        }
        
        //only one stat, add others
        if (m_data.size() == 1) { //get 1%
            TopDeviceData tdOnlyOne = m_data.get(0);
            long lTotal = tdOnlyOne.m_lCount;
            
            TopDeviceData td = new TopDeviceData();
            td.m_fPercentage = tdOnlyOne.m_fPercentage * 0.01f;
            td.m_lCount = Math.max(1, (long)(lTotal * 0.01f));
            td.m_strModelID = OTHERS;
            td.m_strManufacture = OTHERS;
            td.m_strModel = OTHERS;
            
            m_data.add(td);
            
            tdOnlyOne.m_fPercentage -= td.m_fPercentage;
            tdOnlyOne.m_lCount -= td.m_lCount;
        }

        //add one if no current device info
        boolean bHasMyDeviceInfo = false;
        long lMaxCount = Long.MIN_VALUE;
        TopDeviceData tdMax = null;
        for (TopDeviceData td: m_data) {
            if (!bHasMyDeviceInfo && 
                td.m_strModelID.equals(strModelID)) {
                bHasMyDeviceInfo = true;
            }
            if (lMaxCount < td.m_lCount) {
                lMaxCount = td.m_lCount;
                tdMax = td;
            }
        }
        
        //get 1 from max os
        if (!bHasMyDeviceInfo) { 
            m_lDataTime = System.currentTimeMillis();
            
            TopDeviceData td = new TopDeviceData();
            td.m_fPercentage = 1f / lMaxCount;
            td.m_lCount = 1;
            td.m_strModelID = strModelID;
            td.m_strManufacture = strManufacture;
            td.m_strModel = strModel;
            
            m_data.add(td);
            
            tdMax.m_fPercentage -= td.m_fPercentage;
            tdMax.m_lCount -= td.m_lCount;
        }
    }
    
    private void
    _GetTopDeviceStats(boolean bRedownloadFromServer)
    {
        Context ctx = getActivity();
        
        DeviceInfo di = DeviceInfo.GetInstance(ctx);
        final String strDID = di.GetString(DeviceInfoKey.K.UR_ID);
        
        if (m_nType == TYPE_MY_COUNTRY) {
            final String strCountry = di.GetString(DeviceInfoKey.K.UR_COUNTRY);
            HttpConnSrvc.RequestToDeviceOfMyCntyStats(ctx, strCountry, strDID, bRedownloadFromServer);     
        }
        else if (m_nType == TYPE_ALL_COUNTRIES) {
            HttpConnSrvc.RequestTopDeviceOfWorldStats(ctx, strDID, bRedownloadFromServer);  
        }
    }

    @Override protected boolean 
    IsMyDownloadCmd(int nCmd)
    {
        if (m_nType == TYPE_MY_COUNTRY)
            return (nCmd == HttpConnSrvc.CMD_GET_TOP_DEVICE_STATS_MY);
        else if (m_nType == TYPE_ALL_COUNTRIES)
            return (nCmd == HttpConnSrvc.CMD_GET_TOP_DEVICE_STATS_ALL);
        return false;
    }
    
    @Override protected void 
    OnMyDownloadSuccess(int nCmd, JSONObject json)
    {
        super.OnMyDownloadSuccess(nCmd, json);
        
        _SetData(json);
    }
    
    @Override protected void
    SetListItemView(StatData stat, ListItemTagData tag)
    {
        TopDeviceData td = (TopDeviceData)stat;
        
        if (!td.m_strModelID.equals(OTHERS)) {
            tag.m_tvVersion.setText(td.m_strModel);
            tag.m_tvAPI.setText(td.m_strManufacture);
        }
        else {
            tag.m_tvVersion.setText(R.string.others);
            tag.m_tvAPI.setText("");
        }
    }
    
    ////////////////////////////////////
    private static class TopDeviceData extends StatData {
        private String m_strManufacture;
        private String m_strModel;
        private String m_strModelID;
    }
}
